//
//  CocoaSynthAppDelegate.m
//  CocoaSynth
//
//  Created by Jérémy Brault on 06/02/10.
//  Copyright 2010 None. All rights reserved.
//

#import "CocoaSynthAppDelegate.h"
#import "System.h"
#import "PortInProtocol.h"
#import "PortOutProtocol.h"
#import "ConnectorProtocol.h"
#import "SequencerProtocol.h"
#import "ModuleKeyboard.h"
#import "ModuleVCO.h"
#import "ModuleVCOProtocol.h"
#import "ModuleVCF.h"
#import "ModuleVCFProtocol.h"
#import "ModuleVCA.h"
#import "ModuleSpeaker.h"
#import "PortIn.h"
#import "PortOut.h"
#import "Connector.h"
#import "Sequencer.h"
#import "SignalVisualizer.h"
#import "AudioWrapper.h"
#import "SinusoidGenerator.h"
#import "SquareGenerator.h"
#import "SawtoothGenerator.h"
#import "IdentityComputingStrategy.h"
#import "LowpassFilter.h"
#import "Factory.h"
#import "ADSRGenerator.h"
#import "ModuleADSR.h"
#import "VCAAlgorithm.h"
#import "ModuleVCA.h"
#import "BankViewController.h"
#import "MixingViewController.h"
#import "KeyboardViewController.h"
#import "FactoryProtocol.h"
#import "Factory.h"
#import "ModuleWriterProtocol.h"
#import "ModuleWriter.h"
#import "ParametersViewController.h"

@implementation CocoaSynthAppDelegate

#pragma mark - 
#pragma mark Accessors

@synthesize window;
@synthesize bank;
@synthesize mixingTable;
@synthesize keyboard;
@synthesize parameters;

#pragma mark -
#pragma mark NSApplicationDelegate

- (void)applicationDidFinishLaunching:(NSNotification*)aNotification
{
	// Test
	// Modules, ports and connectors initialization
	Module<ModuleKeyboardProtocol>* moduleKeyboard = [[ModuleKeyboard alloc] init];
	Module<ModuleVCOProtocol>* moduleLFO = [[ModuleVCO alloc] init];
	Module<ModuleVCOProtocol>* moduleVCO = [[ModuleVCO alloc] init];
	Module<ModuleVCFProtocol>* moduleVCF = [[ModuleVCF alloc] init];
	Module<ModuleVCAProtocol>* moduleVCA = [[ModuleVCA alloc] init];
	Module<ModuleADSRProtocol>* moduleADSR = [[ModuleADSR alloc] init];
	Module<ModuleSpeakerProtocol>* moduleSpeaker = [[ModuleSpeaker alloc] init];
	
	id<PortOutProtocol> portOutKeyboard = [[PortOut alloc] init];
	id<PortInProtocol> portInLFO = [[PortIn alloc] init];
	id<PortOutProtocol> portOutLFO = [[PortOut alloc] init];
	id<PortInProtocol> portInVCO = [[PortIn alloc] init];
	id<PortOutProtocol> portOutVCO = [[PortOut alloc] init];
	id<PortInProtocol> portInVCF = [[PortIn alloc] init];
	id<PortInProtocol> portFmVCF = [[PortIn alloc] init];
	id<PortOutProtocol> portOutVCF = [[PortOut alloc] init];
	id<PortInProtocol> portInVCA = [[PortIn alloc] init];
	id<PortInProtocol> portInAmVCA = [[PortIn alloc] init];
	id<PortOutProtocol> portOutADSR = [[PortOut alloc] init];
	id<PortOutProtocol> portOutVCA = [[PortOut alloc] init];
	id<PortInProtocol> portInSpeaker= [[PortIn alloc] init];
	
	id<ConnectorProtocol> connectorKeyboardVCO = [[Factory createConnector] retain];
	id<ConnectorProtocol> connectorKeyboardLFO = [[Factory createConnector] retain];
	id<ConnectorProtocol> connectorLFOVCO = [[Factory createConnector] retain];
	id<ConnectorProtocol> connectorLFOVCF = [[Factory createConnector] retain];
	id<ConnectorProtocol> connectorVCOVCF = [[Factory createConnector] retain];
	id<ConnectorProtocol> connectorVCFVCA = [[Factory createConnector] retain];
	id<ConnectorProtocol> connectorADSRVCA = [[Factory createConnector] retain];
	id<ConnectorProtocol> connectorVCASpeaker = [[Factory createConnector] retain];
	id<ConnectorProtocol> connectorToSpeaker = [[Factory createConnector] retain];
	
	[moduleKeyboard addPortOut:portOutKeyboard];
	[moduleLFO addPortOut:portOutLFO];
	[moduleVCO setPortIn:portInVCO];
	[moduleVCO addPortOut:portOutVCO];
	[moduleVCF setPortIn:portInVCF];
	[moduleVCF setCutOffFrequencyPort:portFmVCF];
	[moduleVCF addPortOut:portOutVCF];
	[moduleVCA setPortIn:portInVCA];
	[moduleVCA setPortInAm:portInAmVCA];
	[moduleVCA addPortOut:portOutVCA];
	[moduleADSR addPortOut:portOutADSR];
	[moduleSpeaker setPortIn:portInSpeaker];
	
	/*/ Test N°1 LFO->VCO->Output
	[portInVCO setConnector:connectorLFOVCO];
	[connectorLFOVCO setPortOut:portOutLFO];
	[portInSpeaker setConnector:connectorToSpeaker];
	[connectorToSpeaker setPortOut:portOutVCO];
	//*/
	
	//*/ Test N°2
	[portInVCF setConnector:connectorVCOVCF];
	[connectorVCOVCF setPortOut:portOutVCO];
	[connectorLFOVCF setPortOut:portOutLFO];
	[portInVCA setConnector:connectorVCFVCA];
	[connectorVCFVCA setPortOut:portOutVCF];
	[portInAmVCA setConnector:connectorADSRVCA];
	[connectorADSRVCA setPortOut:portOutADSR];
	[portInSpeaker setConnector:connectorToSpeaker];
	[connectorToSpeaker setPortOut:portOutVCA];
	//*/
	
	//*/ Test N°3
	
	//*
	
	/*/
	[portInVCA setConnector:connectorVCFVCA];
	[connectorVCFVCA setPortOut:portOutVCF];
	[portInAmVCA setConnector:connectorADSRVCA];
	[connectorADSRVCA setPortOut:portOutADSR];
	//*/
	
	
	// Sequencer initialization
	sequencer = [[Sequencer alloc] init];
	[sequencer setIsStarted:NO];
	/*
	[sequencer addModule:moduleKeyboard];
	[sequencer addModule:moduleLFO];
	[sequencer addModule:moduleVCO];
	[sequencer addModule:moduleVCF];
	[sequencer addModule:moduleVCA];
	[sequencer addModule:moduleADSR];
	[sequencer addModule:moduleSpeaker];
	*/
	 
	// Init strategy
	id<ComputingStrategyProtocol> temp = [[[SinusoidGenerator alloc] init] autorelease];
	[temp setModule:moduleLFO];
	[portOutLFO setComputingStrategy:temp];
	temp = [[[SawtoothGenerator alloc] init] autorelease];
	[temp setModule:moduleVCO];
	[portOutVCO setComputingStrategy:temp];
	temp = [[[LowpassFilter alloc] init] autorelease];
	[temp setModule:moduleVCF];
	[portOutVCF setComputingStrategy:temp];
	temp = [[[VCAAlgorithm alloc] init] autorelease];
	[temp setModule:moduleVCA];
	[portOutVCA setComputingStrategy:temp];
	temp = [[[ADSRGenerator alloc] init] autorelease];
	[temp setModule:moduleADSR];
	[portOutADSR setComputingStrategy:temp];
	
	// Set the VCO programmatiquely
	[moduleVCO setBaseFrequency:1000.f];
	[moduleVCO setExponentialFrequency:0.f];
	
	// Set the LFO programmatiquely
	[moduleLFO setBaseFrequency:0.5f];
	[moduleLFO setExponentialFrequency:0.f];
	
	// Set the VCF programmatiquely
	[moduleVCF setInputFrequencyModificator:1.f];
	
	// Set the ADSR programmatiquely
	[moduleADSR setAttack:0.5];
	[moduleADSR setDecay:0.25];
	[moduleADSR setSustain:0.5];
	[moduleADSR setRelease:0.5];
	
	
	// IHM initialisation 
	BankViewController* bankController = [[BankViewController alloc] initWithNibName:@"BankTable" bundle:nil];
	[self.bank setDocumentView:bankController.view];
	
	MixingViewController* mixingController = [[MixingViewController alloc] init];
	[self.mixingTable setDocumentView:mixingController.view];
	
	KeyboardViewController* keyboardController = [[KeyboardViewController alloc] initWithNibName:@"KeyboardTable" bundle:nil];
	[self.keyboard addSubview:keyboardController.view];
	
	ParametersViewController* parametersController = [[ParametersViewController alloc] initWithNibName:@"ParametersTable" bundle:nil];
	[parameters setContentView:parametersController.view];
	
	[mixingController setParameters:parametersController];
	[mixingController setSequencer:sequencer];
	[mixingController setKeyboard:keyboardController];
	
	SignalVisualizer* visualizer = [[SignalVisualizer sharedSignalVisualizer] init];
	
	[display addSubview:visualizer.view];
	
	[window setAcceptsMouseMovedEvents:YES];
	
	// Start
	/*[NSThread detachNewThreadSelector:@selector(start)
							 toTarget:sequencer
						   withObject:nil];
	 */
	/*
	NSOperationQueue* operationQueue = [[NSOperationQueue alloc] init];
	NSInvocationOperation* invocationOperation = [[NSInvocationOperation alloc] initWithTarget:sequencer selector:@selector(start) object:nil];
	[operationQueue addOperation:invocationOperation];
			  
	[operationQueue release];
	operationQueue = nil;
	[invocationOperation release];
	invocationOperation = nil;
	*/
}

- (IBAction)openAction:(id)sender
{
	started = NO;
	[[AudioWrapper sharedWrapper] openOutput];
}

- (IBAction)startStopAction:(id)sender
{
	if (started) {
		[[AudioWrapper sharedWrapper] stopOutput];
		started = NO;
		[sequencer setIsStarted:NO];
	}
	else {
		[[AudioWrapper sharedWrapper] startOutput];
		started = YES;
		[sequencer setIsStarted:YES];
		[NSThread detachNewThreadSelector:@selector(start)
								 toTarget:sequencer
							   withObject:nil];
	}

}

- (IBAction)start:(id)sender
{
	if (!started) {
		[[AudioWrapper sharedWrapper] openOutput];
		[[AudioWrapper sharedWrapper] startOutput];
		[sequencer setIsStarted:YES];
		[NSThread detachNewThreadSelector:@selector(start)
								 toTarget:sequencer
							   withObject:nil];
		[[SignalVisualizer sharedSignalVisualizer] setStarted:YES];
		[NSThread detachNewThreadSelector:@selector(displayOutputSignal)
								 toTarget:[SignalVisualizer sharedSignalVisualizer]
							   withObject:nil];
		started = YES;
	}
}

- (IBAction)stop:(id)sender
{
	if (started) {
		[[AudioWrapper sharedWrapper] stopOutput];
		[[AudioWrapper sharedWrapper] closeOutput];
		[sequencer stop];
		[[SignalVisualizer sharedSignalVisualizer] setStarted:NO];
		started = NO;
	}
}

- (IBAction)closeAction:(id)sender
{
	[[AudioWrapper sharedWrapper] closeOutput];
	started = NO;
}

- (IBAction)displayBigBufferAction:(id)sender
{
	/*
	NSArray* a = [[AudioWrapper sharedWrapper] buffer]; 
	[[SignalVisualizer sharedSignalVisualizer] setSignal:a];
	//*/
	//*
	[NSThread detachNewThreadSelector:@selector(displayOutputSignal)
							 toTarget:[SignalVisualizer sharedSignalVisualizer]
						   withObject:nil];
	//*/
}

- (IBAction)pianoAction:(id)sender
{
	System* s = [System sharedSystem];
	float actualTime = [s time];
	[s setADSRStartTime:actualTime+0.01];
	[s setSustainDuration:5];
}

@end
